///////////////////////////////////////////////////////////
///////////////// Have an itch? Scratch it! ///////////////
///////////////////////// SCRATCH /////////////////////////
/////////////////////  A MUD  Server   ////////////////////
///////////////////// By: Jared Devall ////////////////////
/////////////////////      Thanks:     ////////////////////
/////////////////////  DIKU/Merc/ROM   ////////////////////
///////////////////// Aetas/Deus Gang  ////////////////////
/////////////////////       Beej       ////////////////////
///////////////////////////////////////////////////////////

#include "definitions.h"
#include "timer.h"
#include <sys/time.h>
#include <iostream>
#include <time.h>
#include "timestamp.h"
#include "stringutil.h"
#include "world.h"

Timer::Timer() {
	_enabled = false;
	_interval = 0;
	_when = 0;
}

void Timer::setName( std::string name ) {
	_name = name;
	return;
}

std::string Timer::getName() {
	return _name;
}

void Timer::setEnabled( bool enabled ) {
	_enabled = enabled;
	return;
}

bool Timer::getEnabled() {
	return _enabled;
}

void Timer::setWhen( time_t when ) {
	_when = when;
	return;
}

time_t Timer::getWhen() {
	return _when;
}

void Timer::Reset() {
	time_t current;
	time( &current );
	_when = current + (time_t)_interval;
	return;
}

void Timer::Reset( unsigned long int a ) {
	time_t current;
	time( &current );
	_when = current + (time_t)a;
	return;
}

void Timer::Reset( unsigned long int a, unsigned long int b ) {
	time_t current;
	time( &current );
	_when = current + (time_t)((rand() % b) + a);
	return;
}

bool Timer::Fire() {
	time_t current;
	time( &current );

	if ( _when <= current ) {
		if ( _enabled ) {
			return Execute();
		} else {
			return false;
		}
	} else
		return true;
}

//////////////////////// tick //////////////////////////
Tick::Tick() {
	_name = "tick";
	_enabled = true;
	_interval = 60;
	Reset( LOWER_TICK, UPPER_TICK );
}

Tick::~Tick() { }

bool Tick::Execute() {
	std::string buf;
	time_t current;
	time( &current );

	buf << "tick @ " << Timestamp::Instance().GetDateTime();

	// Check for areas that need to be reset...
	for ( int i=0; i < (int)World::Instance().getAreas().size(); i++ )
		if ( World::Instance().getArea( i )->getNextReset() <= current ) {
			World::Instance().getArea( i )->resetArea();
			buf << "\n\r\tArea \"" << World::Instance().getArea( i )->GetName() << "\" reset.";
		}

	World::Instance().Omninet( buf, TICK, NULL, false );
	Reset( LOWER_TICK, UPPER_TICK );

	return true;
}

//////////////////////// autosave //////////////////////////
Autosave::Autosave() {
	_name = "autosave";
	_enabled = true;
	_interval = 900;
	Reset();
}

Autosave::~Autosave() { }

bool Autosave::Execute() {
	std::string buf;
	time_t current;
	time( &current );

	World::Instance().Save();

	for ( std::list< Character* >::iterator it = World::Instance().getClist().begin(); it != World::Instance().getClist().end(); it++ )
		(*it)->cSave();

	buf << "Autosave @ " << Timestamp::Instance().GetDateTime();
	World::Instance().Omninet( buf, STANDARD, NULL, false );
	std::cerr << buf << '\n';

	Reset( _interval );

	return true;
}

//////////////////////// autobackup //////////////////////////
Autobackup::Autobackup() {
	_name = "autobackup";
	_enabled = true;
	_interval = 86400;
	Reset();
}

Autobackup::~Autobackup() { }

bool Autobackup::Execute() {
	std::string file;
	std::string command;
	std::string command2;
	std::string stamp;
	std::string buf;

	// Archive system data...
	stamp = Timestamp::Instance().backupTime();
	file << "backups/backup_" << stamp << ".tar.gz";
	command << "tar -cf " << file << " system log";
	system( command.c_str() );

	// Set permissions...
	command2 << "chmod -Rf 700 backups";
	system( command2.c_str() );

	buf << "Autobackup @ " << Timestamp::Instance().GetDateTime();
	World::Instance().Omninet( buf, STANDARD, NULL, false );
	std::cerr << buf << '\n';

	Reset( _interval );

	return true;
}

//////////////////////// autoreboot //////////////////////////
Autoreboot::Autoreboot() {
	_name = "autoreboot";
	_enabled = true;
	_interval = 604800; // Seven days
	_stage = FIVE;
	_fiveMinuteWarning = 0;
	_thirtySecondWarning = 0;
	_countdownThree = 0;
	_countdownTwo = 0;
	_countdownOne = 0;
	_countdownOver = 0;
	setWarningTimers();
}

Autoreboot::~Autoreboot() { }

void Autoreboot::setWarningTimers() { // private
	time_t current;
	time( &current );

	// Set initial _when value to a five minute warning.
	_when = current + (time_t)_interval;
	_fiveMinuteWarning = current + (time_t)_interval - (time_t)300;
	_thirtySecondWarning = current + (time_t)_interval - (time_t)30;
	_countdownThree = current + (time_t)_interval - (time_t)3;
	_countdownTwo = current + (time_t)_interval - (time_t)2;
	_countdownOne = current + (time_t)_interval - (time_t)1;
	_countdownOver = current + (time_t)_interval;

	return;
}

bool Autoreboot::Execute() {
	std::string buf;
	time_t current;
	time( &current );

	switch ( _stage ) {
		case FIVE:
			std::cerr << "SYSTEM: 5 minutes until autoreboot.\n";
			World::Instance().Broadcast( "5 minutes until automated system reboot.\n\r", CONNECTED );
			_when = _thirtySecondWarning;
			break;
		case THIRTY:
			std::cerr << "SYSTEM: 30 seconds until autoreboot.\n";
			World::Instance().Broadcast( "30 seconds until automated system reboot.\n\r", CONNECTED );
			_when = _countdownThree;
			break;
		case THREE:
			std::cerr << "SYSTEM: 3 seconds until autoreboot.\n";
			World::Instance().Broadcast( "3 seconds until automated system reboot.\n\r", CONNECTED );
			_when = _countdownTwo;
			break;
		case TWO:
			std::cerr << "SYSTEM: 2 seconds until autoreboot.\n";
			World::Instance().Broadcast( "2 seconds until automated system reboot.\n\r", CONNECTED );
			_when = _countdownOne;
			break;
		case ONE:
			std::cerr << "SYSTEM: 1 second until autoreboot.\n";
			World::Instance().Broadcast( "1 second until automated system reboot.\n\r", CONNECTED );
			_when = _countdownOver;
			break;
		case REBOOT:
			std::cerr << "SYSTEM: Autoreboot.\n";
			World::Instance().Copyover();
			break;
		default:
			std::cerr << "ERROR: \"bool Autoreboot::Execute( void )\" -> switch ( _stage ) hit default.\n";
			World::Instance().Omninet( "Error with automatic system reboot timer \"bool Autoreboot::Execute( void ) -> switch ( _stage ) hit default\"", STANDARD, NULL, true );
			break;
	}

	_stage++;

	return true;
}
